<div style="padding: 20px;">
    <h1>API设计</h1>
    <h2>API分类标准</h2>
    <div style="padding-left: 8px;">1. 是否对外开放</div>
    <div style="padding-left: 40px; font-size: 12px;">决定了API的访问途径</div>
    <div style="padding-left: 8px;">2. 是否需要验证</div>
    <div style="padding-left: 40px; font-size: 12px;">决定了API访问时是否需要用户登录</div>
    <div style="padding-left: 8px;">3. 是否与其他团队共享</div>
    <div style="padding-left: 40px; font-size: 12px;">决定了是否需要参与生命周期管理</div>
    <h2>API具体类别</h2>
    <div style="padding-left: 8px;">1. 内部API</div>
    <div style="padding-left: 40px; font-size: 12px;">团队后端内部使用，通过注册中心直接调用，不享受相关服务</div>
    <div style="padding-left: 8px;">2. 外部公共非共享API</div>
    <div style="padding-left: 40px; font-size: 12px;">对外开放，允许任意人任意调用，享受相关服务</div>
    <div style="padding-left: 8px;">3. 外部公共共享API</div>
    <div style="padding-left: 40px; font-size: 12px;">对外开放，允许任意人任意调用，享受相关服务，与生命周期管理</div>
    <div style="padding-left: 8px;">4. 外部保护非共享API</div>
    <div style="padding-left: 40px; font-size: 12px;">对外开放，需要验证，享受相关服务</div>
    <div style="padding-left: 8px;">5. 外部保护共享</div>
    <div style="padding-left: 40px; font-size: 12px;">对外开放，需要验证，享受相关服务，与生命周期管理</div>
    <h2>共享与订阅</h2>
    <div style="padding-left: 8px;">1. 您可以选择将API共享，允许别人发现并订阅</div>
    <div style="padding-left: 8px;">2. 您可以订阅共享API，提交请求并批复后可以按照申请的额度来消费</div>
    <h2>API过期</h2>
    <div style="padding-left: 8px;">共享API无法像普通API那样被直接删除，您需要先将其设定为过期，这样您API的订阅者会收到过期通知，然后您可以执行删除操作</div>
    <h2>API限流</h2>
    <div style="padding-left: 8px;">1. 外部公开API</div>
    <div style="padding-left: 40px; font-size: 12px;">以IP为单位进行限流，不论项目，拥有者可以更改额度配置</div>
    <div style="padding-left: 8px;">1. 外部保护API</div>
    <div style="padding-left: 40px; font-size: 12px;">以项目，用户为单位进行限流，可以通过订阅请求来申请额度</div>
    <h1>异常设计</h1>
    <h2 style="padding-left: 8px; font-weight: 700;">异常类：DefinedRuntimeException</h2>
    <div style="padding-left: 8px;">所有系统已知异常抛出此类，该类允许自定义错误信息，http代码，错误代码，错误分类</div>
    <div style="padding-left: 8px;">备注：<a href="./docs/error">错误码查询表</a></div>
    <h1>软删除还是硬删除</h1>
    <div style="padding-left: 8px;">1. 随着项目变得越来越复杂，软删除变得越来越难以管理</div>
    <div style="padding-left: 8px;">2. 软删除后，数据仍存在，唯一联合索引需要特别处理</div>
    <div style="padding-left: 8px;">3. 希望暂时保留被删除数据，用于用户误操作恢复以及数据分析</div>
    <div style="padding-left: 8px;">方案：默认采用硬删除，特例采用软删除，新增删除审计日志以及被删除数据写入特定数据库</div>
    <h1>分布式任务</h1>
    <div style="padding-left: 8px;">1. 分布式任务在同一时刻只能在一个节点执行</div>
    <div style="padding-left: 8px;">2. 监控任务长时间未执行</div>
    <div style="padding-left: 8px;">3. 监控任务多次执行报错</div>
    <div style="padding-left: 8px;">已知问题：项目启动时会报任务饥饿，因为初始化时任务一定会被判定饥饿（长时间未执行）</div>
    <div style="padding-left: 8px;">已知问题：若任务执行花费过久，会导致其余线程一直无法获得锁而不停报任务线程饥饿</div>
    <div style="padding-left: 8px;">已知问题：高频率任务，会激烈的竞争锁，例如事件扫描</div>
    <h1>事件驱动架构</h1>
    <div style="padding-left: 8px;">一次事务中新增的事件通过异步线程来投递到消息队列中</div>
    <div style="padding-left: 8px;">为什么抛弃分布式任务？1.事件扫描频率过高，激烈的锁竞争。2.当无新事件写入时，数据库也在被不停的读取。3.无论数据库扫描如何短，一方面增加数据库压力，另一方面无法做到及时投递</div>
    <div style="padding-left: 8px;">已知问题：事件有时会被重复投递（二次扫描和一次扫描同时发生），重复投递的事件有概率会消费失败（并发插入），会收到消息拒绝的站内信</div>
    <div style="padding-left: 8px;">已知问题：事件数量过多后，事件处理时间变长，事件被投递到消息队列的时间间隔变长</div>
    <h1>开发规范</h1>
    <div style="padding-left: 8px;">git branch名称：feature/**,bugfix/**,release/2023-03-31</div>
    <div style="padding-left: 8px;">git commit规范：小的，有意义的，能读懂的commit message 例如：update property to fix foo</div>
    <h1>RESTful-获取数据的两种方式</h1>
    <div style="padding-left: 8px;">GET /resource/$id 返回400错误码，找不到资源,等价于get by id</div>
    <div style="padding-left: 8px;">GET /resource?query=id:$id 找不到资源返回200空body，等价于query by id</div>
    <h1>RESTful</h1>
    <div style="padding-left: 8px;">数据必须分页 GET /resource?query=page:0,size:50</div>
    <h1>校验策略</h1>
    <div style="padding-left: 8px;">Resource层，Application层：无自定义校验逻辑</div>
    <div style="padding-left: 8px;">Domain层：三层校验</div>
    <div style="padding-left: 8px;">核心思路：通过创建Domain 对象来进行3层校验逻辑</div>
    <h1>项目架构（六边形）</h1>
    <div style="padding-left: 8px;">Resource层：Restful接口层</div>
    <div style="padding-left: 8px;">Application层：事务，锁，幂等层</div>
    <div style="padding-left: 8px;">Domain层：业务逻辑</div>
    <div style="padding-left: 8px;">Infrastructure层：底层依赖实现层</div>
    <div style="padding-left: 8px;">Port.adapter层：外部依赖管理层</div>
    <div style="padding-left: 8px;">核心思路：清晰的外部依赖，内部依赖，资源暴露与只注重业务逻辑的业务层</div>
    <h1>懒加载</h1>
    <div style="padding-left: 8px;">对象一律默认懒加载，如果需要一次性获取值则单独写query，例如loadClientByClientId</div>
    <h1>命名规范</h1>
    <div style="padding-left: 8px;">get vs query，get表示拿取，query则表示查询</div>
    <h1>hibernate设计</h1>
    <div style="padding-left: 8px;">hibernate适用于简单的应用场景</div>
    <div style="padding-left: 8px;">当需要高度定制化读取数据库时，hibernate不是很好用</div>
    <div style="padding-left: 8px;">反序列化时会越过某些setter中的校验逻辑</div>
    <div style="padding-left: 8px;">hibernate的改动会有延迟机制，烦人的on release of batch it still contained JDBC statement</div>
    <h1>properties</h1>
    <div style="padding-left: 8px;">mt.mgmt.email=</div>
    <div style="padding-left: 8px;">mt.common.url.lock=</div>
    <div style="padding-left: 8px;">mt.common.url.message-queue=</div>
    <div style="padding-left: 8px;">mt.common.url.database=</div>
    <div style="padding-left: 8px;">mt.common.domain-name=</div>
    <div style="padding-left: 8px;">mt.common.instance-id=</div>
    <div style="padding-left: 8px;">mt.feature.oauth.jwt.password=</div>
    <div style="padding-left: 8px;">mt.feature.oauth.jwt.alias=</div>
    <div style="padding-left: 8px;">mt.feature.oauth.jwt.key-store=</div>
    <div style="padding-left: 8px;">mt.feature.proxy-reload=</div>
    <div style="padding-left: 8px;">mt.feature.email.type=</div>
    <div style="padding-left: 8px;">mt.feature.sms.type=</div>
    <div style="padding-left: 8px;">mt.feature.log.sql=</div>
</div>
